// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*!
\file
\brief Implementation of BitString utility functions 
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "bitstring.h"

BitString new_BitString(long numbits)
{
	BitString bs = NULL;
	long size;
	size = BitStringsize(numbits);
	bs = (BitString) malloc(sizeof(unsigned int) * size);
	if (bs != NULL) memset(bs, 0, size*sizeof(unsigned int));

	return bs;
}

void BitStringset0(BitString bs, long begin, long numbits)
{
	long bbkind, bbtind, size;
	unsigned int mask;

	size =BitStringsize(numbits);
	bbkind = begin / BITBULKSIZE;
	bbtind = begin % BITBULKSIZE;
	if(bbkind >= size) return; // out of range!

	/* set the beginning bulk */
	mask = 0x0; mask = ~mask; /* 111...111 */
	mask = ~(mask << bbtind); /* 000...111 */
	bs[bbkind] &= mask;

	/* not last bulk */
	if(bbkind != (size-1)) 
		memset(bs+bbkind+1, 0, sizeof(unsigned int)*(size-bbkind-1));

}

void BitStringsetall1(BitString bs, long numbits)
{		
	long i, size;
	size =BitStringsize(numbits);

	//set all to 1
	memset(bs, 0, size*sizeof(unsigned int));	
	for(i=0;i<size;i++)
		bs[i] = ~bs[i];
	
	//set to 0 from the numbits th bit to the end
	if(numbits< (long) (size*BITBULKSIZE))
		BitStringset0(bs, numbits, numbits);
}


void BitStringset1(BitString bs, long pos)
{
	unsigned int mask;

	mask = 0x1;
	mask = mask << (pos % BITBULKSIZE);
	bs[pos/BITBULKSIZE] |= mask;
}

long BitStringgetnum1s(BitString bs, long numbits)
{
	long i, j, size;
	unsigned int mask, resv;
	long count;

	size =BitStringsize(numbits);
	count = 0;
	for(i=0; i<size; i++)
	{
		if(bs[i] != 0)
		{
			mask = 0x1;
			for(j=0; j<BITBULKSIZE; j++)
			{
				resv = bs[i] & mask;
				if(resv !=0) count++;
				mask = mask << 1;
			}
		}
	}
	return count;
}

void BitStringcopy(BitString srcbs, BitString desbs, long numbits)
{
	memcpy(desbs, srcbs, sizeof(unsigned int)*BitStringsize(numbits));
}

BOOL BitStringgetbit(BitString bs, long pos)
{
	unsigned int mask;

	if(bs == NULL) return 0;

	mask = 0x1;
	mask = mask << (pos % BITBULKSIZE);
	mask = bs[pos/BITBULKSIZE] & mask;
	
	return (mask !=0) ? TRUE : FALSE;
}

int BitStringIsSuperset(BitString s1, BitString s2, long numbits)
{
	long i, size;
	size =BitStringsize(numbits);

	for(i=0; i<size; i++)
		if((s1[i] & s2[i]) != s2[i])  
			return 0;
	return 1;
}


int BitStringcmp(BitString s1, BitString s2, long numbits)
{
	int issame;
	long i, size;

	size =BitStringsize(numbits);
	issame = 0;
	for(i=0; i<size; i++)
		if(s1[i] > s2[i])
		{
			issame = 1;
			break;
		}
		else if(s1[i] < s2[i]) 
		{
			issame = -1;
			break;
		}

	return issame;
}


void BitStringand(BitString bs1, BitString bs2, long numbits)
{
	long i, size;
	size = BitStringsize(numbits);

	for(i=0; i<size; i++)
		bs1[i] &= bs2[i];
}


int BitStringisall0(BitString bs, long begin, long end)
{
	long i, begpos, endpos;
	unsigned int mask, resv;

	begpos= begin/BITBULKSIZE;
	endpos= end/BITBULKSIZE;

	// Check middle part first
	for(i= begpos+1; i<endpos; i++)
		if(bs[i] !=0)  return 0;

	// Check first and last part
	//if all bits in a single bulk
	if(begpos == endpos)
	{
		mask=0; mask= ~mask;
		mask = mask << (begin % BITBULKSIZE);
		resv = mask & bs[begpos];
		mask=0; mask= ~mask;
		mask = mask >> (BITBULKSIZE - end%BITBULKSIZE - 1);
		resv = mask & resv;
		return (resv !=0)? 0 : 1;
	}
	else
	{
		// first part
		mask=0; mask= ~mask;
		mask = mask << (begin % BITBULKSIZE);
		mask &= bs[begpos];
		if(mask !=0)
			return  0;
		else
		{	// last part
			mask=0; mask= ~mask;
			mask = mask >> (BITBULKSIZE - end%BITBULKSIZE - 1);
			mask &= bs[endpos];
			return (mask !=0)? 0 : 1;
		}
	}
}


void BitStringprint(BitString bs, long numbits)
{
	long i;
	for(i=0; i<numbits; i++)
	{
		//if(i%4==0) printf(" ");
		printf("%d", BitStringgetbit(bs,i));
	}
	printf("\n");
}

BitString BitString_create(long numbits, int *allocatedStorage) 
{
	BitString bs = NULL;
	long size;
	int _allocatedStorage = 0;

	size = BitStringsize(numbits);
	_allocatedStorage = sizeof(unsigned int) * size;

	if (allocatedStorage != NULL) *allocatedStorage = _allocatedStorage;

	bs = (BitString) malloc(_allocatedStorage);
	if (bs != NULL) memset(bs, 0, size*sizeof(unsigned int));

	return bs;
}
